// -*- coding: utf-8 -*-

#include <string>

#include <boost/bind.hpp>

#include "elisa/elisa.h"
#include "elisa/hybrid/hybrid.h"
//#include "hybrid/parser/hybrid_expr_visitor.h"

using namespace std;
using namespace elisa;

int main(int argc, char *argv[]) 
{
	elisa::init();
	elisa::RealVar::SetPrecision(1.0e-1);
	elisa::RealVar::SetDigits(16);

	elisa::useHybridNewton(true);
	elisa::useBC5();

	// 求解パラメタ
	elisa::RealVar::SetPrecision(1.0e-1);
	Time::setPrecision(1.0e-2);


	HybridParser parser;
	bool res = false;
	if (argc == 1)
		res = parser.parseStream(cin);
	else if (argc == 2)
		res = parser.parseFile(argv[1]);
	if (!res)
		return EXIT_FAILURE;

	// 変数
	ContVarVec cvv;
	std::vector<RealExpr> rev;
	VarMap::iterator vit(parser.variables().begin());
	for (; vit != parser.variables().end(); ++vit) {
		cvv.push_back(&(*vit->second));
		rev.push_back(*vit->second);
	}

	Time t(v_bias::interval(0.0), cvv, 0.0, parser.time().sup());

	// 連続制約
	ContConstraint cc(new ContConstraintRep(cvv, t, HybridParser::dFunc, HybridParser::dFunc),
					  boost::bind(&HybridParser::gFunc<VNInterval>, parser, _1, _2),
					  boost::bind(&HybridParser::gFunc<AD_VNInterval>, parser, _1, _2),
					  HybridParser::dFunc<VNInterval>);

	// ガード制約
	elisa::RealConstraint ac;
	ac = elisa::RealConstraint(boost::bind(&HybridParser::gFunc<RealExpr>, parser, 
										   _1, _2)(rev, t) == 0);

	// モデル
	Model model(cc && ac);
	//Model model(ac);

	// ソルバー
	elisa::IntervalSolver solver(model);

	elisa::ueReset();

	// 求解処理
	try {
		while (solver.next()) {
			cout << "Solution " << solver.numSolutions() << endl;
			cout << "\tt in " << *t.getDomain() << endl;

			VarMap::const_iterator vit;
			for (vit = parser.variables().begin(); vit != parser.variables().end(); ++vit) {
				//cout << '\t' << vit->second->getName() << " in " << *vit->second->getDomain() << endl;
				//cout << '\t' << vit->second->getName() << " in " << parser.rFunc(vit->second->getName(), rev) << endl;

				string n(vit->second->getName());
				if (parser.rExprMap().find(n) == parser.rExprMap().end()) {
					cout << '\t' << n << " in " << *vit->second->getDomain() << endl;
				} else {
					HybridExprVisitor<RealExpr> vst(parser, rev);
					vst.visit(*parser.rExprMap()[n]->rep());
					RealExpr e(*vst.value());
					NaturalIntervalFormVisitor v;
					v.visit(*e.rep());
					Interval rv(v.node()->eval());

					cout << '\t' << n << " in " << rv << endl;
				}
			}
		}
	} catch (std::string& msg) {
		cout << "an exeption occured: " << msg << endl;
	}

	if (!solver.numSolutions()) 
		cout << "NO SOLUTION" << endl;
	else 
		cout << solver.numSolutions() << " solution(s)" << endl;

#ifdef ELISA_PROFILE
	cout << "split: " << solver.numSplit() << endl;
	cout << "boxes: " << solver.numProcessedBoxes() << endl;
#endif

	elisa::dismiss();

	return EXIT_SUCCESS;
}
